週一早上,James 開完主管週會回到座位。
「James,糟糕了!」小艾慌張的跑來找 Jame。「PO init 程式整個 Hang 住了!」
James 放下筆記本,跟著小艾到他的座位,看小艾以 VNC 開啟的 Server 畫面,PO init 一直掛在那邊。
「已經半小時了,都沒有動靜!」小艾說著。
「都沒有錯誤訊息嗎?嗯...先把 PO init 的 Process 停掉。小艾,打開專案檔,我們 Trace 一下程式。」James 要小艾開啟 Visual Studio 專案,開始抓蟲動作。
從 SQL 語法的確認到迴圈中每一個 m 的值的追蹤,都正確無誤。
「沒道理啊,這些語法都對,怎麼會出現 Hang 住的狀況?」James 與小艾看著執行的結果。
「ERP 有出現 Table Lock(註1) 嗎?可是也不可能一直咬著啊!而且有 Error 發生的話,也會產生 Exception 啊!」James 嘀咕著,回到座位,想要看一下 ERP Server 的狀況。
喬安這時也走過來,「James,早上 User 也反應無法 Key 採購單,我看 Informix 的連線狀況,好像跟之前外部程式連結當掉的狀況很像。」
經喬安提醒,James 想到問題可能發生的原因,於是跟小艾說,「小艾,你程式中是不是有加 Transaction?」
小艾檢查程式,果然在建立 Connection 的時候,有加上 Transaction。
CONN.ConnectionString = IIf(My.Settings.isDebug, My.Settings.ERPConnectionString_Debug, My.Settings.ERPConnectionString)
CONN.Open()
trans = CONN.BeginTransaction
James 先解釋造成 Lock 的原因給小艾聽,「當有兩個 Transaction Transaction 1 與 Transaction 2 同時針對同一個 Resource 存取時,先存取的 Transaction 1 會先將資源 Lock 住,後面進來的 Transaction 2 就會等在那邊,並嘗試做 Locking, 如果這時候 Transaction 1 當掉或者 Timeout 掉,但 Resource 沒有 Release 出來時,Transaction 2 還是在等待當中,這時候再有新的 Transaction ,就會造成 Dead Lock」(圖1)
圖1:Transaction Lock 說明(資料來源:http://www.cubrid.org/transaction_and_lock)
「可是我看之前的程式有加入 Transaction,而且加上 Transaction 不是可以確保資料 Update 的一致性?」小艾疑惑。
「一般來說,一個 Connection 中有兩個交易,而這兩個交易有關連的時候,要確保兩個交易資料的同步,才會加入 Transaction,以採購簽核這個 Case,如果更新失敗,下一次排程會再讀取上次沒成功的資料,所以在這邊不需要加入 Transaction。」James 向小艾說明通常 Transaction 的用途。
「而且我們這套 ERP 用的是 Informix 的資料庫,異動時資料庫會做 Table Lock,如果助理 Key 單 Key 到一半,沒有離開輸入畫面,這樣 Lock 會一直存在,這時候外部的連結都無法運作,我想應該是我們外部連結的 Transaction 在讀取資料時,剛好遇到 User 在輸入資料,產生 wait locking 之後程式 Waiting 太久當掉,所以造成兩邊的程式都 Hang 住。」
小艾將 Transaction 的程式碼 mark 掉之後,重新 Compiler 程式,再次執行的結果,就正常了。
James 接著說明,「關於 Informix 這個問題,一直找不到解決的方法,向原廠問,原廠的回覆是一定會做 Table Lock,而且是要確保資料的正確性?Google 或查 Forum 查到的大部分指向當初建立 Table 時採用的 Lock 方式,或者是 SQL 語法撰寫的問題,但 ERP 整個系統這麼大,我們也不可能一個一個去試。」
「像 SQL Server 的 T-SQL 就提供 with (nolock),相當於 READUNCOMMITTED, 就是當別人在 Update 資料時,透過這種方式來 Select 資料時,可以不受 Transaction 的限制,當然這得視情況而定,在多人上線的環境,如果不要求資料的即時與正確性的時候,就可以採用這種方式來提升查詢的效能。」(註2)
select * from Table WITH (nolock)
「另外,我剛注意到,你在 Console 中沒有做資訊的 Output,這樣 Runtime 的時候,並不知道程式到底執行了什麼,或者有什麼狀況發生。」
「可以透過 Console.WrLine() 將訊息輸出。還有,將 Messagebox 拿掉吧,在 Server 上執行,訊息是要給誰看?」James 與小艾相視而笑,這一次的危機就在歡笑聲中解除。
註1:Informix 關於 Lock 的說明,有些是 SQL 語法的問題,有些是建立 Table 時指定的 Lock 方式。
註2:有關 SQL Server nolock 的演繹及說明可參考 Understanding the SQL Server NOLOCK hint
iT邦幫忙MVPantijava提到:
真美好的工作氣氛
可能背後有小說般暗潮汹湧....
這樣泰大都看得出來...
jamesjan提到:
這樣泰大都看得出來...
只能怪賽大太陽大的小說太太太太太精采了....
ted99tw提到:
只能怪賽大太陽大的小說太太太太太精采了
真的 ...
jamesjan提到:
「而且我們這套 ERP 用的是 Informix 的資料庫,異動時資料庫會做 Table Lock,如果助理 Key 單 Key 到一半,沒有離開輸入畫面,這樣 Lock 會一直存在,這時候外部的連結都無法運作,我想應該是我們外部連結的 Transaction 在讀取資料時,剛好...(恕刪)
交易的原則是儘量縮短時間, 在過程中不要包入人工作業...時間會過長或人為變數過多
Dead Lock 通常是2個交易以上互咬造成死結....
看 Jame大 領導風格, 風淡雲清, 不疾不徐....令人賞心悦目...
謝謝 charmmih 大的鼓勵